package com.zoe.onelink.auth.token.processor.impl;

import com.zoe.onelink.auth.token.processor.OnelinkTokenFallbackProvider;
import com.zoe.onelink.auth.token.processor.OnelinkTokenInfoProcessor;
import com.zoe.onelink.common.enumeration.ExceptionCodeEnum;
import com.zoe.onelink.common.exception.ApiException;
import io.lettuce.core.RedisCommandTimeoutException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.client.circuitbreaker.CircuitBreaker;
import org.springframework.dao.QueryTimeoutException;

import java.util.Map;

/**
 * <p>标题: </p>
 * <p>描述: </p>
 * <p>版权: Copyright (c) 2023</p>
 * <p>公司: 智业软件股份有限公司</p>
 *
 * @version: 1.0
 * @author: ruansheng
 * @date: 2023-01-29
 */
@Slf4j
@RequiredArgsConstructor
public class OnelinkCircuitBreakerTokenInfoProcessor implements OnelinkTokenInfoProcessor {


    private final OnelinkLocalCachedRedisTokenInfoProcessor localCachedRedisTokenInfoProcessor;
    private final OnelinkTokenFallbackProvider onelinkTokenFallbackProvider;
    private final CircuitBreaker circuitBreaker;

    @Override
    public Map<String, Object> process(String onelinkToken) {
        // 如果断路器不存在直接使用Redis和本地缓存
        if (this.circuitBreaker == null) {
            return this.localCachedRedisTokenInfoProcessor.process(onelinkToken);
        }
        return this.circuitBreaker.run(() -> this.localCachedRedisTokenInfoProcessor.process(onelinkToken), exception -> {
            // 业务异常直接抛出
            if (exception instanceof ApiException) {
                throw (ApiException) exception;
            }
            // Redis超时已经记录警告日志即可
            if (exception instanceof QueryTimeoutException || exception instanceof RedisCommandTimeoutException) {
                log.warn("[OnelinkToken] Redis查询超时: {}", exception.getMessage());
            }
            if (exception instanceof RuntimeException) {
                // 如果没有配置容错处理器则直接抛出异常
                if (this.onelinkTokenFallbackProvider == null) {
                    throw (RuntimeException) exception;
                }
                if (log.isDebugEnabled()) {
                    log.debug("[OnelinkToken] 使用容错处理机制解析Token");
                }
                try {
                    // 尝试使用容错处理器解析TOKEN
                    return this.onelinkTokenFallbackProvider.onFallback(onelinkToken);
                } catch (Exception e) {
                    throw ApiException.createEx(ExceptionCodeEnum.TOKEN_PARSE_FAILURE);
                }
            }
            throw new RuntimeException(exception);
        });
    }
}
